home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
fish
/
751-760
/
758
/
bformat
/
bformat.c
< prev
next >
Wrap
Text File
|
1995-03-18
|
20KB
|
873 lines
/*
** This is a further modification to the Bformat program developed by
** Bob Bush. This generation now allows the formatting of any device
** using either file system. It still maps out bad sectors, but does it
** a sector at a time instead of a track at a time. This is particularly
** useful for the formatting of hard disks.
**
** The command format is:
** BFormat DRIVE <drive> NAME <name> [FFS|NOFFS] [FAST|QUICK|SLOW] [QuIeT]
** please note that the format is strictly enforced. All field must be
** specified in the specified order.
*/
/* bformat.c */
/*
When you format a diskette dos grabs 2 blocks for its own use.
Block 880 is the Root block. Block 881 (normally on a fresh format) is
the bitmap which in itself indicates the blocks that are available for use
or currently in use. Generally, a '1' bit means the corresponding block
is available. A '0' bit means that the block is in use. This sounds
relatively simple but the AmigaDos implementation needs some
explanation.
AmigaDos Block Allocation Map (512 bytes -or- 128 longwords)
------------------------------------------------------------
LongWord Usage
-------- -----
0 location of the block checksum
1 first bitmap allocation longword, which breaks down as follows:
hi-order bit (31) lo-order bit (0)
/ /
| |
11111111111111111111111111111111 (32 bit longword)
\\ \\\
\\_block #32 \\\_block #2
\_block #33 \\_block #3
\_block #4
(The above example indicates that blocks 2 thru 33 are available for use)
You might wonder why the bitmap starts at block #2 and not block #0?
I suppose since the first 2 blocks of every disk are not available for
file storage, AmigaDos simply chooses to ignore the fact that they exist.
Another reason could be that if the bitmap included blocks zero and one,
it might be too easy to figure out.. Hmmmmm..
Actually I think it corresponds to the well documented (ha) Mountlist
parameter named 'Reserved' which can be used to segment a hard disk into
more than one logical drive If you look at it in that light, the first
bit in the bitmap corresponds to a block number which is the same as the
number of 'Reserved' blocks in the Mountlist file.. Have yet to verify
this on my hard disk but it sounds logical. ( Note from Tom Nery -
Unfortunately the 2 block offset is not related to the 'Reserved'
parameter, It was a good guess though).
Inany case, the remainder of the bitmap looks the same e.g. the next
longword (lo order bit) starts the map for block #34 -- and so on, until
the map terminates at block #1760...
With the above info, you should be able to figure out how this program
works.
*/
/*
Date Programmer Modification
========= ========== =============================================
91-Feb-10 T.A.Nery Removed support for '-C' option but added
support for all mounted disk type devices,
including FFS. Also added support for various
levels of disk verificaition.
88-Aug-18 R.W.Bowers Created this header, added Execute "code" above
88-Aug-15 R.W.Bowers Fixed a "minor" BUG! Using the -C[heck]
option "erased" the entire disk!!
88-Aug-14 R.W.Bowers Changed reporting from "Track xx" to
"Cyl yy, Head z"
88-Jul-10 R.W.Bowers Changed # tracks from 160 to "Tracks"
88-Jul-10 R.W.Bowers Compiles under Lattice 4.0 or, with -dMANX,
under MANX
88-Mar-28 Bob Bush cpu-73105,1332 - compiled with Lattice 4.0
*/
#include "exec/types.h"
#include "exec/nodes.h"
#include "exec/lists.h"
#include "exec/memory.h"
#include "exec/interrupts.h"
#include "exec/ports.h"
#include "exec/libraries.h"
#include "exec/io.h"
#include "exec/tasks.h"
#include "exec/execbase.h"
#include "exec/devices.h"
#include "devices/trackdisk.h"
#include "intuition/intuition.h"
#include "libraries/dos.h"
#include "libraries/dosextens.h"
#include "libraries/filehandler.h"
#include "stdio.h"
#include <string.h>
#define DONE 0
#define CONT 1
#define FAILURE 0
#define SUCCESS 1
#define OLD 0x444f5300L
#define FFS 0x444f5301L
#define FAST 1
#define QUICK 2
#define SLOW 3
#define NEXT_DEVICE(device) ((struct DosList *) BADDR(device->dol_Next))
struct INFO {
char Drive[80]; /* Drive Name (eg. df0:) */
char Label[80]; /* Disk Label (eg. Empty) */
char Device[80]; /* Device Name (eg. trackdisk.device) */
int Unit; /* Device's unit number, per mountlist */
long Sectors; /* Number of Sectors per track */
long Surfaces; /* Number of Surfaces */
long LoCyl; /* Starting Cylinder number */
long HiCyl; /* Ending Cylinder number */
long FileSystem; /* File system being used */
/* 0x444f5300 - Old File System */
/* 0x444f5301 - Fast File System */
};
extern struct DosLibrary *DOSBase;
struct INFO Info;
BOOL formatting = FALSE;
ULONG bitmap_size; /* Number of bytes allocated to init the bitmaps */
long *buffer,*bitmap,*track = NULL;
short abort;
long TestPattern[4] ={0xFFFFFFFFL, 0xAAAAAAAAL, 0x55555555L, 0x00000000L};
struct IOStdReq *mreq = NULL;
struct MsgPort *mport,*dosport = NULL;
struct StandardPacket *dpacket; /* packet for dos */
int Verify_mode;
int Quiet;
/*
** Convert a BPCL string to a 'C' style string
*/
int convert_bstr(out,in,colon)
BYTE *in;
char *out;
int colon;
{
if ((*in >= 59) || (*in == 0))
return(FALSE);
memcpy(out, in+1, *in);
if (colon == TRUE)
{
out[*in] = ':';
out[(*in)+1] = '\0';
}
else
out[*in] = '\0';
return(TRUE);
}
void write_block(block,buff)
long block;
long *buff;
{
mreq->io_Length = 512;
mreq->io_Data = (APTR)buff;
mreq->io_Command = CMD_WRITE;
mreq->io_Offset = block * 512;
DoIO(mreq);
}
void Update()
{
mreq->io_Length = 1;
mreq->io_Command = CMD_UPDATE;
DoIO(mreq);
}
int Clear()
{
mreq->io_Length = 0;
mreq->io_Command = CMD_CLEAR;
DoIO(mreq);
return(0);
}
/*
** Check for the existence of the specified device. If found, set the
** default format parameters for the specific mountlist entry.
*/
int check_dev(dev,drive)
struct DeviceNode *dev;
char drive[];
{
struct FileSysStartupMsg *startup;
char Name[80];
ULONG *dosenv;
if (convert_bstr(Name,BADDR(dev->dn_Name),TRUE) == TRUE)
{
if (stricmp(Name,drive) == 0)
{
strcpy(Info.Drive,Name);
}
else
return(FAILURE);
}
else
return(FAILURE);
startup = (struct FileSysStartupMsg *)(BADDR(dev->dn_Startup));
Info.Unit = startup->fssm_Unit;
if (convert_bstr(Name,BADDR(startup->fssm_Device),FALSE) == TRUE)
{
strcpy(Info.Device,Name);
}
dosenv = (ULONG *) (BADDR(startup->fssm_Environ));
Info.Sectors = dosenv[5];
Info.Surfaces = dosenv[3];
Info.LoCyl = dosenv[9];
Info.HiCyl = dosenv[10];
Info.FileSystem = OLD;
if (dosenv[16] == FFS)
Info.FileSystem = FFS;
return(SUCCESS);
}
void cmd_error()
{
printf("\nCommand Format Error. Command Syntax is:\n");
printf(" BFormat DRIVE <drive> NAME <name> [FFS|NOFFS] [FAST|QUICK|SLOW] [QuIeT]\n");
exit(10);
}
int check_struct(dev,drive)
struct DosList *dev;
char drive[];
{
if ((dev->dol_Type) == DLT_DEVICE)
if (check_dev(dev,drive) == SUCCESS)
return(DONE);
return(CONT);
}
int verify(drive)
char drive[];
{
struct RootNode *rootNode;
struct DosInfo *dosInfo;
struct DosList *firstDevice, *device;
rootNode = (struct RootNode *) DOSBase->dl_Root;
dosInfo = (struct DosInfo *) BADDR(rootNode->rn_Info);
firstDevice = (struct DosList *) BADDR(dosInfo->di_DevInfo);
for (device = firstDevice ; device ; device = NEXT_DEVICE(device))
{
if (check_struct(device,drive) == DONE)
return(SUCCESS);
}
printf("\nDrive %s Not Found", drive);
return(FAILURE);
}
int chk_params(cnt,args)
int cnt;
char *args[];
{
int i;
/* Check if the correct number of arguments */
if (cnt < 5)
return(FAILURE);
/* Make sure all keywords are valid */
if (stricmp(args[1],"DRIVE"))
return(FAILURE);
else if (verify(args[2]) != SUCCESS)
return(FAILURE);
if (stricmp(args[3],"NAME"))
return(FAILURE);
else
strcpy(Info.Label,args[4]);
Verify_mode = QUICK;
Quiet = FALSE;
for (i = 5 ; i < cnt ; ++i)
{
if (stricmp(args[i],"FFS") == 0)
Info.FileSystem = FFS;
else if (stricmp(args[i],"NOFFS") == 0)
Info.FileSystem = OLD;
else if (stricmp(args[i],"SLOW") == 0)
Verify_mode = SLOW;
else if (stricmp(args[i],"QUICK") == 0)
Verify_mode = QUICK;
else if (stricmp(args[i],"FAST") == 0)
Verify_mode = FAST;
else if (strcmp(args[i],"QuIeT") == 0)
Quiet = TRUE;
else
return(FAILURE);
}
return(SUCCESS);
}
void inhibit(t)
long t; /* true or false */
{
struct MsgPort *handler;
struct StandardPacket *packet = dpacket ;
handler = (struct MsgPort *)DeviceProc(Info.Drive);
if (!((handler == NULL) || (dosport == NULL)))
{
packet->sp_Msg.mn_Node.ln_Name = (char *)&(packet->sp_Pkt);
packet->sp_Pkt.dp_Link = &(packet->sp_Msg);
packet->sp_Pkt.dp_Port = dosport;
packet->sp_Pkt.dp_Type = ACTION_INHIBIT;
packet->sp_Pkt.dp_Arg1 = t;
PutMsg(handler, packet);
WaitPort(dosport);
GetMsg(dosport);
}
}
void cleanup(err)
int err;
{
inhibit(FALSE);
if(mreq)
{
CloseDevice(mreq);
DeleteStdIO(mreq);
}
if(mport)
DeletePort(mport);
if(dosport)
DeletePort(dosport);
if(dpacket)
FreeMem(dpacket,sizeof(struct StandardPacket));
if(bitmap)
FreeMem(bitmap,bitmap_size);
if(buffer)
FreeMem(buffer,512);
if(track)
FreeMem(track,512 * Info.Sectors);
exit(0);
}
/* handle ctrl-c, ctrl-d aborts */
int brk()
{
int c;
char buf[20];
if(formatting)
{
printf("\n***
Break
***");
printf("\nDo you really want to abort (y/n)? ");
gets(buf); c = buf[0];
if (c == 'y' || c == 'Y')
{
printf(
"\n
Warning!
Disk may be unusable.\n\n");
cleanup(0); /* Was cleanup(999); */
}
else
abort = 0;
return(0);
}
}
void format_track(tnum)
int tnum;
{
mreq->io_Length = 512 * Info.Sectors;
mreq->io_Data = (APTR)track;
mreq->io_Command = TD_FORMAT;
mreq->io_Offset = tnum * Info.Sectors * 512;
DoIO(mreq);
}
void write_track(tnum)
int tnum;
{
mreq->io_Length = 512 * Info.Sectors;
mreq->io_Data = (APTR)track;
mreq->io_Command = CMD_WRITE;
mreq->io_Offset = tnum * Info.Sectors * 512;
DoIO(mreq);
}
void set_fbuff(buff,sectors,value)
ULONG buff[];
int sectors;
long value;
{
int j;
for(j = 0; j < (128 * sectors);j++)
buff[j] = value;
}
/* verify track with abort on critical tracks */
int verify_track(tnum)
int tnum;
{
int test;
int length;
length = 512 * Info.Sectors;
if (Verify_mode == SLOW)
{
for (test = 0 ; test < 4 ; ++test)
{
set_fbuff(track,Info.Sectors,TestPattern[test]);
write_track(tnum);
mreq->io_Length = length;
mreq->io_Data = (APTR)track;
mreq->io_Command = CMD_READ;
mreq->io_Offset = tnum * Info.Sectors * 512;
DoIO(mreq);
if ((mreq->io_Error) || (mreq->io_Actual != length))
return(0);
}
}
else if (Verify_mode == QUICK)
{
mreq->io_Length = length;
mreq->io_Data = (APTR)track;
mreq->io_Command = CMD_READ;
mreq->io_Offset = tnum * Info.Sectors * 512;
DoIO(mreq);
if ((mreq->io_Error) || (mreq->io_Actual != length))
return(0);
}
else
{
mreq->io_Length = 512;
mreq->io_Data = (APTR)track;
mreq->io_Command = CMD_READ;
mreq->io_Offset = tnum * Info.Sectors * 512;
DoIO(mreq);
if ((mreq->io_Error) || (mreq->io_Actual != 512))
return(0);
}
return(1);
}
void chk_abort()
{
if (SetSignal(0L, (ULONG) (SIGBREAKF_CTRL_C)) & (SIGBREAKF_CTRL_C))
brk();
}
void validate_required()
{
int fstat;
int sel_track;
/* chk_abort(); */
/*
** First calculate the starting track number
*/
sel_track = Info.LoCyl * Info.Surfaces;
/*
** Verify that track 0 is usable.
*/
set_fbuff(track,Info.Sectors,Info.FileSystem);
format_track(sel_track);
/* chk_abort(); */
formatting = TRUE;
if (!(fstat = verify_track(sel_track)))
{
printf("\n
Unable to format track #0. ");
printf("Disk not useable.
\n\n");
cleanup(100);
}
/*
** Now calculate the Root Block's track number
*/
sel_track += (((Info.HiCyl - Info.LoCyl + 1) * Info.Surfaces)/2);
/*
** Verify that root block track is usable.
*/
format_track(sel_track);
if (!(fstat = verify_track(sel_track)))
{
printf("\n
Unable to format root block. ");
printf("Disk not useable.
\n\n");
cleanup(100);
}
}
/* mark block as allocated (in use) */
void clear_bitmap(block)
long block;
{
long lindex;
if ((block - 2) > -1)
{
lindex = (block - 2) / 32;
bitmap[lindex] = bitmap[lindex] & (~(1 << ((block-2) % 32)));
}
}
/* mark block as available for use */
void set_bitmap(block)
int block;
{
int lindex;
if ((block - 2) > -1)
{
lindex = (block - 2) / 32;
bitmap[lindex] = bitmap[lindex] | (1 << ((block-2) % 32));
}
}
/* mark track as available */
int set_track(tnum)
int tnum;
{
int j;
mreq->io_Command = TD_PROTSTATUS;
DoIO(mreq);
if(mreq->io_Actual)
{
printf("Disk Write Protected!\n");
printf("\n
Warning!
Disk may be unusable.\n\n");
cleanup(0); /* Was cleanup(999); */
return(0);
}
for(j = (tnum * Info.Sectors) ;
j < (tnum * Info.Sectors + Info.Sectors);j++)
set_bitmap(j);
}
/* set volume name into root block (BCPL string) */
void set_name(dest,vname)
char *dest,*vname;
{
*dest = (char)strlen(vname);
dest++;
while(*vname)
{
*dest = *vname;
dest++; vname++;
}
}
void zblock(wp) /* clear buffer to zeros */
ULONG wp[];
{
int j;
for(j = 0; j < 128; j++)
wp[j] = 0;
}
/* checksum= 2's complement of sum of all words in block */
ULONG check_sum(buff)
ULONG buff[];
{
int j;
ULONG cksum;
cksum = 0;
for(j = 0; j < 128; j++)
cksum += buff[j]; /* sum all words in block */
return(-cksum);
}
/* build initialized root block */
void init_root(wp,vname,blk)
ULONG wp[];
char *vname;
long blk;
{
int i, bit_blks;
ULONG temp;
temp = 0;
bit_blks = bitmap_size/512;
wp[5] = 0;
zblock(wp);
wp[0] = 0x02; /* type */
wp[3] = 0x48; /* hashtable size */
wp[78] = 0xffffffff; /* 'true' bitmap flag */
for (i = 1 ; i <= bit_blks ; ++i)
wp[78+i] = blk + i;
DateStamp(&wp[105]); /* datestamp */
set_name(&wp[108],vname); /* disk name (BCPL) string */
DateStamp(&wp[121]); /* datestamp */
wp[127] = 0x01; /* secondary type = root */
wp[5] = check_sum(wp); /* create root block checksum */
}
void init_bitmap(wp,root_block)
ULONG wp[];
long root_block;
{
int i, bit_blks;
bit_blks = bitmap_size/512;
clear_bitmap(root_block); /* set root block to allocated */
for (i = 1; i <= bit_blks ; ++i)
clear_bitmap(root_block + i);
}
/*
** Inhibits dos from trying to access drive while we have control. Also puts
** up DF0:BUSY message, causes dos to re-read disk info on termination.
*/
int Checkstat()
{
mreq->io_Command = TD_CHANGESTATE;
DoIO(mreq);
if(mreq->io_Actual)
{
printf("No Disk In Drive!\n");
return(1);
}
mreq->io_Command = TD_PROTSTATUS;
DoIO(mreq);
if (mreq->io_Actual)
{
printf("Disk Write Protected!\n");
return(1);
}
return(0);
}
void format_it()
{
int error,fstat,badcount;
int bytes, i, j;
int block_cnt, cyl_cnt;
int block_start, cyl, head, trk;
char c;
long *map_p, block_num, track_size;
badcount = 0;
cyl_cnt = Info.HiCyl - Info.LoCyl + 1;
block_cnt = cyl_cnt * Info.Sectors * Info.Surfaces;
track_size = Info.Sectors * 512;
block_start = Info.LoCyl * Info.Sectors * Info.Surfaces;
if (Quiet != TRUE)
{
printf("\nDrive =
%s
Name =
%s
\n",
Info.Drive, Info.Label);
printf("Insert Disk to be
FORMATTED
in drive %s.\n",
Info.Drive);
printf("Press Return when ready: ");
c = getchar();
}
chkabort();
if(!(mport = (struct MsgPort *)CreatePort("FLOPPY0",0)))
cleanup(100);
if(!(dosport = (struct MsgPort *)CreatePort("DOSPORT",0)))
cleanup(100);
if(!(mreq = (struct IOStdReq *)CreateStdIO(mport)))
cleanup(100);
if(!(dpacket=(struct StandardPacket *)
AllocMem(sizeof(struct StandardPacket), MEMF_PUBLIC|MEMF_CLEAR)))
cleanup(100);
if(error = OpenDevice(Info.Device,Info.Unit,mreq,0))
cleanup(1);
inhibit(TRUE);
/* chk_abort(); */
/*
** Determine how many blocks are required for bitmap, then allocate them
** Block size calculations based upon 508 byte blocks, since the first
** four bytes of each block are for checksum.
*/
bytes = block_cnt/8;
for (bitmap_size = 508 ; bitmap_size < bytes ; bitmap_size += 508) ;
/*
printf("\nBitmap_size = %d Bytes or %d Blocks\n",
bitmap_size,bitmap_size/508);
*/
bitmap_size = bitmap_size / 508 * 512;
if(!(bitmap = (long *)AllocMem(bitmap_size, MEMF_CLEAR | MEMF_CHIP)))
cleanup(8);
if(!(buffer = (long *)AllocMem(512,MEMF_CLEAR | MEMF_CHIP)))
cleanup(8);
if(!(track = (long *)AllocMem(track_size,MEMF_CLEAR | MEMF_CHIP)))
cleanup(8);
if (Checkstat())
cleanup(100);
/* chk_abort(); */
validate_required();
for (cyl = Info.LoCyl ; cyl <= Info.HiCyl ; ++cyl)
{
if (Quiet != TRUE)
printf("Formatting Cylinder %d
\n",cyl);
for (head = 0 ; head < Info.Surfaces ; ++head)
{
trk = cyl * Info.Surfaces + head;
format_track(trk);
/* chk_abort(); */
}
if (Quiet != TRUE)
printf("Verifying Cylinder %d
\n",cyl);
for (head = 0 ; head < Info.Surfaces ; ++head)
{
trk = cyl * Info.Surfaces + head;
if (!(fstat = verify_track(trk)))
{
badcount += Info.Sectors;
}
else
{
trk = (cyl - Info.LoCyl)
* Info.Surfaces + head;
set_track(trk);
}
/* chk_abort(); */
}
}
if (Quiet != TRUE)
printf("\n%d Sectors Allocated as Bad\n",badcount);
/* init boot/root/bitmap blocks and write to disk.. */
set_fbuff(buffer,1,Info.FileSystem);
write_block(block_start, buffer);
set_fbuff(buffer,1,Info.FileSystem);
write_block(block_start+1, buffer);
/* Root block is middle of device */
block_num = block_cnt/2 + block_start;
init_root(buffer,Info.Label,(long)(block_cnt/2));
/* printf("Writing Root Block, #%d\n",block_num); */
write_block(block_num, buffer);
init_bitmap(bitmap,block_cnt/2);
for (i = 1, map_p = (long *)bitmap ;
i <= (bitmap_size/512) ; ++i, map_p += 128)
{
/* calculate checksum for each block and insert */
for (j = 0 ; j < 127 ; ++j)
buffer[j + 1] = map_p[j];
buffer[0] = 0;
buffer[0] = check_sum(buffer);
/* printf("Writing Bitmap Block, #%d\n",block_num+i); */
write_block((long)(block_num + i), buffer);
}
Update();
Clear();
mreq->io_Length = 0;
mreq->io_Command = TD_MOTOR; /* turn off motor */
DoIO(mreq);
cleanup(0);
}
main(cnt,argi l;
);
Clea );
n( Ino; ++head)
{
"p ;
to (ean.o*/
DoIcnt, cyl_cn);
rrum 2Tj)
bufferu
main" 8d\n",al)8 *|f,tSC3f (!(&rack(
initor>.ºh128)
Lotor */
D,tSCu
{dlock and insert */
for (j = 0 ; j mea ));
lida,ru
c (bitmap_size x ));
lida,rmapu0= 0o"p ru Bytes crify_t(0)*culate<, #Q(eaQ(ea*at *0)))
ck aÐ4C3f (!(&¤(
inj = bl = bl = bl aÐ4j(block_startn
LId1T 0 ,();8i; bitmapap =gngtha iniblock10= gc0i)8 *|fe fice= bl = bl = bl aÐ4jÆoitm; + m; Rgc+ m; Rgco,;nbym(!(eeeck(bl)u8to (map_size)8 *|f gck.. * .ºh128)
Lotock0_u#Q(eaQ(7t
riteingtha